#include "ReaderTopoConvertHelper.h"
#include "cone.hxx"
#include "edge.hxx"
#include "common/logger.h"
#include "ellipse.hxx"
#include "intcurve.hxx"
#include "plane.hxx"
#include "sphere.hxx"
#include "straight.hxx"
#include "helix.hxx"
#include <common/PointT.hpp>
#include <topology/TopoEdge.hpp>
#include <topology/TopoFace.hpp>
#include "geometry/Geom3Line.hpp"
#include "math/CurveCalculation.hpp"
#include "geometry/Geom3TrimmedCurve.hpp"
#include "geometry/MakeGeom3Ellipse.hpp"
#include "geometry/MakeGeom3Circle.hpp"
#include "geometry/Geom3BSplineCurve.hpp"
#include "geometry/Geom3Plane.hpp"
#include "geometry/MakeGeom3Plane.hpp"
#include "geometry/MakeGeom3CylindricalSurface.hpp"
#include "geometry/MakeGeom3ConicalSurface.hpp"
#include "geometry/Geom3SphericalSurface.hpp"
#include "geometry/Geom3ToroidalSurface.hpp"
#include <geometry/Geom3BSplineSurface.hpp>
#include <geometry/Geom3TrimmedSurface.hpp>
#include "topology/TopoBuilder.hpp"
#include "modeling/MakeEdge.hpp"
#include "modeling/MakeFace.hpp"
#include "sp3crtn.hxx"
#include "getowner.hxx"
#include "sps3srtn.hxx"
#include "sps3crtn.hxx"
#include "sp3srtn.hxx"
#include "face.hxx"
#include "surface.hxx"
#include "spline.hxx"
#include "common/Array2.hpp"
#include "torus.hxx"
#include <occtio/OCCTTool.hpp>
#include "spldef.hxx"

AMCAX_EXCHANGE_NAMESPACE_BEGIN

namespace  InterOp::ReaderGeometryConvertHelper{


AMCAX::Point3 ConvertPoint(const SPAposition &position) 
{
    return AMCAX::Point3(position.x(),position.y(),position.z());
}

void ConvertKnotAndMult(const std::vector<double> &input,
    std::vector<double> &newKnot, std::vector<int> &newMult)
{
    // NOTE:转成符合amcax要求的knot和mult
    // knot数组保存input去重后的结果，顺序与input一致
    // mult数组保存knot元素的重复次数
    std::unordered_map<double, int> tempMap;
    std::unordered_map<double, bool> flagMap;

    for (double num : input)
    {
        tempMap[num]++;
        if (!flagMap[num])
        {
            newKnot.emplace_back(num); // 按顺序加入去重的值
            flagMap[num] = true;       // 标记该值已经处理
        }
    }

    for (double val : newKnot)
    {
        newMult.emplace_back(tempMap[val]);
        // LOG_DEBUG("pair.first:{} pair.second:{}.", val, tempMap[val]);
    }
}

void GetBsplineParameters(const FACE *face)
{
    // LOG_DEBUG("bspline parameters");
    SURFACE * S = face->geometry();
    const surface & s = S->equation();
    bs3_surface bs3 = ((const spline&)s).sur();

    // 获取样条曲面参数
    int dim, rational_u, rational_v, form_u, form_v, pole_u, pole_v, ctrl_num_u, ctrl_num_v;
    SPAposition *ctr_point_pos = nullptr;
    double *weights = nullptr;
    int degree_u = 0, degree_v = 0;
    int num_knots_u = 0, num_knots_v = 0;
    double *knots_u, *knots_v = nullptr;
    bs3_surface_to_array(bs3,
    dim, rational_u, rational_v, form_u, form_v, pole_u, pole_v,
    ctrl_num_u, ctrl_num_v, ctr_point_pos, weights,
    degree_u, num_knots_u, knots_u, degree_v, num_knots_v, knots_v);
    bool periodic_u = bs3_surface_periodic_u(bs3);
    bool periodic_v = bs3_surface_periodic_v(bs3);

    // LOG_DEBUG("dim:{}", dim);
    // LOG_DEBUG("rational_u:{}, form_u:{}, pole_u:{}.",  rational_u, form_u, pole_u);
    // LOG_DEBUG("rational_v:{}, form_v:{}, pole_v:{}.", rational_v, form_v, pole_v);
    // LOG_DEBUG("ctrl_num_u:{}, degree u:{}, knot_count_u:{}, periodic_u:{}.", ctrl_num_u, degree_u, num_knots_u, periodic_u);
    // LOG_DEBUG("ctrl_num_v:{}, degree_v:{}, knot_count_v:{}, periodic_v:{}.", ctrl_num_v, degree_v, num_knots_v, periodic_v);

    // 控制点转amcax
    AMCAX::Array2<AMCAX::Point3> amcax_ctrl_points(ctrl_num_u, ctrl_num_v);
    for (int i = 0; i < ctrl_num_u; i++)
    {
        std::vector<AMCAX::Point3> tmp_vector;
        tmp_vector.reserve(ctrl_num_v);
        for (int j = 0; j < ctrl_num_v; j++)
        {
            SPAposition pos = ctr_point_pos[i * ctrl_num_v + j];
            tmp_vector.emplace_back(pos.x(), pos.y(), pos.z());
            // LOG_DEBUG("[{},{}]:({}, {}, {}),", i,j,pos.x(), pos.y(), pos.z());
        }
        amcax_ctrl_points.FillRow(i, tmp_vector);
    }
    if (ctr_point_pos != nullptr)
    {
        delete[] ctr_point_pos;
    }

    if(weights != nullptr)
    {
        // 权重转amcax
        AMCAX::Array2<double> weights_array(ctrl_num_u, ctrl_num_v);
        for (int i = 0; i < ctrl_num_u; i++)
        {
            std::vector<double> tmp_vector;
            tmp_vector.reserve(ctrl_num_v);
            for (int j = 0; j < ctrl_num_v; j++)
            {
                // LOG_DEBUG("W[{},{}]:{}", i, j, weights[i * ctrl_num_v + j]);
                tmp_vector.emplace_back(weights[i * ctrl_num_v + j]);
            }
            weights_array.FillRow(i, tmp_vector);
        }
    }

    // u方向的knots和mult
    std::vector<double> knot_vec_u;
    knot_vec_u.reserve(num_knots_u);
    for (int i = 0; i < num_knots_u; i++)
    {
        double *pos = knots_u + i;
        knot_vec_u.emplace_back(*pos);
    }
    std::vector<double> newKnots_u;
    std::vector<int> newMults_u;
    ConvertKnotAndMult(knot_vec_u, newKnots_u, newMults_u);

    // v方向的knots和mult
    std::vector<double> knot_vec_v;
    knot_vec_v.reserve(num_knots_v);
    for (int i = 0; i < num_knots_v; i++)
    {
        double *pos = knots_v + i;
        knot_vec_v.emplace_back(*pos);
    }
    std::vector<double> newKnots_v;
    std::vector<int> newMults_v;
    ConvertKnotAndMult(knot_vec_v, newKnots_v, newMults_v);

    for(int i = 0; i < newKnots_u.size(); i++)
    {
    // LOG_DEBUG("newKnots_u:{} newMults_u:{}.", newKnots_u[i], newMults_u[i]);
    }

    for(int i = 0; i < newKnots_v.size(); i++)
    {
    // LOG_DEBUG("newKnots_v:{} newMults_v:{}.", newKnots_v[i], newMults_v[i]);
    }

    // LOG_DEBUG("bspline parameters done.");
}

void GetBcurveParameters(const bs3_curve *appox_cur){
    // LOG_DEBUG("bs3curve parameters");
    int ctrl_point_count = 0;

    // 获取样条曲线参数
    SPAposition *ctr_point_pos = nullptr;
    int dim, degree, rational;
    double *weights = nullptr;
    int knot_count = 0;
    double *knot_pos = nullptr;
    bs3_curve_to_array(*appox_cur, dim, degree, rational, ctrl_point_count, ctr_point_pos, weights, knot_count, knot_pos);
    bool isPeriodic = bs3_curve_periodic(*appox_cur);
    // LOG_DEBUG("dim:{}, degree:{}, rational:{}, ctrl_point_count:{}, knot_count:{},periodic:{}.", dim, degree, rational, ctrl_point_count, knot_count,isPeriodic);

    // 控制点转amcax
    for (int i = 0; i < ctrl_point_count; i++)
    {
        SPAposition *pos = ctr_point_pos + i;
        // LOG_DEBUG("[{}]:({}, {}, {})", i,pos->x(), pos->y(), pos->z());
    }
    if (ctr_point_pos != nullptr)
    {
        delete[] ctr_point_pos;
    }

    // knots和mult
    std::vector<double> knot_vec;
    knot_vec.reserve(knot_count);
    for (int i = 0; i < knot_count; i++)
    {
        double *pos = knot_pos + i;
        knot_vec.emplace_back(*pos);
    }
    std::vector<double> newKnots;
    std::vector<int> newMults;
    ConvertKnotAndMult(knot_vec, newKnots, newMults);
    for(int i = 0; i < newKnots.size(); i++)
    {
    // LOG_DEBUG("newKnots:{} newMults:{}.", newKnots[i], newMults[i]);
    }

    // weights 转vector
    if(weights!=nullptr){
    // LOG_DEBUG("weights bcurve");
        for(int i=0;i<ctrl_point_count;i++){
        // LOG_DEBUG("weight[{}]:{}",i,weights[i]);
        }
    }

    // LOG_DEBUG("bs3curve parameters done");


}

}

namespace  InterOp::ReaderTopoConvertHelper{


AMCAX::TopoEdge ConvertCoedge(const COEDGE *coedge,bool coedgeReverse)
{
    if (!coedge) {
        LOG_ERROR("coedge is null");
        return AMCAX::TopoEdge();
    }

    EDGE *edge = coedge->edge();
    if (!(edge->geometry()))
    {
        LOG_ERROR("edge geometry is null");
        return AMCAX::TopoEdge();
    }
    else
    {
        return ConvertEdge(edge,coedgeReverse);
    }
}

AMCAX::TopoEdge ConvertEdge(const EDGE *edge,bool coedgeReverse,bool edgeReverse)
{
    if (!edge) {
        LOG_ERROR("edge is null");
        return AMCAX::TopoEdge();
    }

    AMCAX::TopoEdge topoEdge;
    CURVE *curve = edge->geometry();
    if (curve == nullptr)
    {
        return topoEdge;
    }

    if(is_STRAIGHT(curve)){
        return ConvertStraightLine(edge,coedgeReverse,edgeReverse);
    }

    if (is_ELLIPSE(curve)) {
        return ConvertEllipse(edge,coedgeReverse,edgeReverse);
    }

    if (is_INTCURVE(curve)) {
        return ConvertIntcurve(edge,coedgeReverse,edgeReverse);
    }

    if (is_HELIX(curve)) {
        return ConvertHelix(edge,coedgeReverse,edgeReverse);
    }
    LOG_ERROR("not support curve type: {},", curve->type_name());
    return topoEdge;
}

AMCAX::TopoEdge ConvertStraightLine(const EDGE *edge,bool coedgeReverse,bool edgeReverse)
{
    if (!edge) {
        LOG_ERROR("edge is null");
        return AMCAX::TopoEdge();
    }    

    AMCAX::Point3 startPoint = InterOp::ReaderGeometryConvertHelper::ConvertPoint(edge->start_pos());
    AMCAX::Point3 endPoint = InterOp::ReaderGeometryConvertHelper::ConvertPoint(edge->end_pos());

    
    if (startPoint.IsEqual(endPoint, AMCAX::Precision::Confusion()))
    {
        return AMCAX::TopoEdge();
    }

    AMCAX::Line3 a_line(startPoint, AMCAX::Direction3(AMCAX::Vector3(startPoint, endPoint)));
    double t1 = AMCAX::CurveCalculation::Parameter(a_line, startPoint);
    double t2 = AMCAX::CurveCalculation::Parameter(a_line, endPoint);

    auto gLine = std::make_shared<AMCAX::Geom3Line>(a_line);
    auto straight = std::make_shared<AMCAX::Geom3TrimmedCurve>(gLine, t1, t2);

    AMCAX::TopoBuilder TB;
    AMCAX::TopoEdge res = AMCAX::MakeEdge(straight);
    res.SetOrientation(edgeReverse? OrientationType::Reversed:OrientationType::Forward);
    TB.UpdateEdge(res,gLine, AMCAX::Precision::Confusion());
    return res;
}

AMCAX::TopoEdge ConvertCircle(const EDGE *edge,bool coedgeReverse,bool edgeReverse)
{
    if (!edge) {
        LOG_ERROR("Invalid edge") ;
        return TopoEdge() ;
    }
    ELLIPSE *curve = static_cast<ELLIPSE *>(edge->geometry());
    if (!curve) {
        LOG_ERROR("Invalid curve") ;
        return TopoEdge() ;
    }

    const SPAvector majAxis = curve->major_axis();
    double radius = sqrt(majAxis.x() * majAxis.x() + majAxis.y() * majAxis.y() + majAxis.z() * majAxis.z());
    // SPAposition root_pos = curve->centre();
    SPAunit_vector rootNorm = curve->normal();

    // AMCAX::Point3 circle_center(root_pos.x(), root_pos.y(), root_pos.z());
    AMCAX::Point3 circleCenter = ReaderGeometryConvertHelper::ConvertPoint(curve->centre()) ;
    AMCAX::Direction3 dirNormal(rootNorm.x(), rootNorm.y(), rootNorm.z());
        
    AMCAX::MakeGeom3Circle makeCircleCurve(circleCenter, dirNormal, radius);
    // 圆弧
    std::shared_ptr<AMCAX::Geom3Circle> cirRes = makeCircleCurve.Value();

    if (!edge->closed())
    {
        // SPAposition start_pos = edge->start_pos();
        // SPAposition end_pos = edge->end_pos();

        // AMCAX::Point3 amcax_start_pos(start_pos.x(), start_pos.y(), start_pos.z());
        // AMCAX::Point3 amcax_end_pos(end_pos.x(), end_pos.y(), end_pos.z());
        AMCAX::Point3 amcaxStartPosition = ReaderGeometryConvertHelper::ConvertPoint(edge->start_pos());
        AMCAX::Point3 amcaxEndPosition = ReaderGeometryConvertHelper::ConvertPoint(edge->end_pos());
        
        auto coedgeRev = (bool)(edge->coedge()->sense() == REVERSED);
        if(edge->sense() == REVERSED)
        {
            cirRes->Reverse();
        }

        double t1 = AMCAX::CurveCalculation::Parameter(cirRes->Circle(), amcaxStartPosition);
        double t2 = AMCAX::CurveCalculation::Parameter(cirRes->Circle(), amcaxEndPosition);

        TopoEdge res=AMCAX::MakeEdge(std::make_shared<AMCAX::Geom3TrimmedCurve>(cirRes, t1, t2));
        AMCAX::TopoBuilder TB; 
        res.SetOrientation(coedgeReverse? OrientationType::Reversed:OrientationType::Forward);
        TB.UpdateEdge(res,cirRes, AMCAX::Precision::Confusion());
        return res;
    }
    return AMCAX::MakeEdge(cirRes);
}

AMCAX::TopoEdge ConvertEllipse(const EDGE *edge,bool coedgeReverse,bool edgeReverse)
{
    ELLIPSE *curve = static_cast<ELLIPSE *>(edge->geometry());

    if (std::fabs(curve->radius_ratio() - 1.0) < 1e-6)
    {
        return ConvertCircle(edge,coedgeReverse,edgeReverse);
    }

    const SPAvector majAxis = curve->major_axis();
    SPAunit_vector tmpNorm = curve->normal();
    SPAposition tmpCenter = curve->centre();
    double majorLength = sqrt(majAxis.x() * majAxis.x() + majAxis.y() * majAxis.y() + majAxis.z() * majAxis.z());
    double minor_length = curve->radius_ratio() * majorLength;

    AMCAX::Coord3 dirNormal(tmpNorm.x(), tmpNorm.y(), tmpNorm.z());         
    AMCAX::Coord3 dirToMajorPoint(majAxis.x(), majAxis.y(), majAxis.z());
    AMCAX::Coord3 dirToMinorPoint = dirNormal.Cross(dirToMajorPoint).Normalize();

    AMCAX::Point3 ellipseCenter(tmpCenter.x(), tmpCenter.y(), tmpCenter.z());
    AMCAX::Point3 ellipseNearPoint(tmpCenter.x() + minor_length * dirToMinorPoint.X(),
                                        tmpCenter.y() + minor_length * dirToMinorPoint.Y(), tmpCenter.z() + minor_length * dirToMinorPoint.Z());

    AMCAX::Point3 ellipseFarPoint(tmpCenter.x() + majAxis.x(),
                                    tmpCenter.y() + majAxis.y(), tmpCenter.z() + majAxis.z());

    AMCAX::MakeGeom3Ellipse makeEllipseCurve(ellipseFarPoint, ellipseNearPoint, ellipseCenter);

    std::shared_ptr<AMCAX::Geom3Ellipse> cirRes = makeEllipseCurve.Value();
    if (!edge->closed())
    {
        AMCAX::Point3 amcaxStartPosition = ReaderGeometryConvertHelper::ConvertPoint(edge->start_pos());
        AMCAX::Point3 amcaxEndPosition = ReaderGeometryConvertHelper::ConvertPoint(edge->end_pos());

        if(edgeReverse)
        {
            cirRes->Reverse();
        }
        
        double t1 = AMCAX::CurveCalculation::Parameter(cirRes->Ellipse(), amcaxStartPosition);
        double t2 = AMCAX::CurveCalculation::Parameter(cirRes->Ellipse(), amcaxEndPosition);

        TopoEdge res=AMCAX::MakeEdge(std::make_shared<AMCAX::Geom3TrimmedCurve>(cirRes, t1, t2));
        AMCAX::TopoBuilder TB; 
        res.SetOrientation(coedgeReverse? OrientationType::Reversed:OrientationType::Forward);
        TB.UpdateEdge(res,cirRes, AMCAX::Precision::Confusion());

        return res;
    }
    return AMCAX::MakeEdge(cirRes);
}

AMCAX::TopoEdge ConvertHelix(const EDGE *edge,bool coedgeReverse,bool edgeReverse)
{
    if (!edge) {
        LOG_ERROR("edge is null");
        return TopoEdge() ;   
    }
    if (!edge->geometry()) {
        LOG_ERROR("helix geometry is null");
        return TopoEdge() ;   
    }

    double startParam = double(edge->start_param());
    double endParam = double(edge->end_param());
    const helix *helixCurve = static_cast<const helix *>(&(edge->geometry()->equation()));
    
    bs3_curve appoxCur = bs3_curve_make_hel(*helixCurve, startParam, endParam);
    TopoEdge res =  ConvertEdgeFromBs3curve(&appoxCur);
    res.SetOrientation(coedgeReverse? OrientationType::Reversed:OrientationType::Forward);
    return res;
}

AMCAX::TopoEdge ConvertIntcurve(const EDGE *edge,bool coedgeReverse,bool edgeReverse)
{

    if (!edge) {
        LOG_ERROR("edge is null");
        return TopoEdge() ;   
    }
    if (!edge->geometry()) {
        LOG_ERROR("helix geometry is null");
        return TopoEdge() ;   
    }

    curve* edgeCurve = edge->geometry()->trans_curve(get_owner_transf(edge),edgeReverse);   
    bs3_curve appoxCur;
    double startParam = edge->start_param();
    double endParam = edge->end_param();
    appoxCur = bs3_curve_make_cur(*edgeCurve, startParam, endParam);
    TopoEdge res = ConvertEdgeFromBs3curve(&appoxCur);
    res.SetOrientation(coedgeReverse? OrientationType::Reversed:OrientationType::Forward);

    return res;
}

AMCAX::TopoEdge ConvertEdgeFromBs3curve(const bs3_curve *curve)
{

    ReaderGeometryConvertHelper::GetBcurveParameters(curve);
    int ctrl_point_count = 0;

    // 获取样条曲线参数
    SPAposition *ctr_point_pos = nullptr;
    int dim, degree, rational;
    double *weights = nullptr;
    int knot_count = 0;
    double *knot_pos = nullptr;
    bs3_curve_to_array(*curve, dim, degree, rational, ctrl_point_count, ctr_point_pos, weights, knot_count, knot_pos);
    bool isPeriodic = bs3_curve_periodic(*curve);

    // 控制点转amcax
    std::vector<AMCAX::Point3> amx_ctrl_point;
    amx_ctrl_point.reserve(ctrl_point_count);
    for (int i = 0; i < ctrl_point_count; i++)
    {
        SPAposition *pos = ctr_point_pos + i;
        amx_ctrl_point.emplace_back(AMCAX::Point3(pos->x(), pos->y(), pos->z()));
    }
    if (ctr_point_pos != nullptr)
    {
        delete[] ctr_point_pos;
    }

    // weights 转vector
    std::vector<double> weights_vector;
    if(weights!=nullptr){
        // LOG_DEBUG("weights bcurve");
        for(int i = 0;i < ctrl_point_count;i++){
            weights_vector.push_back(weights[i]);
        }
    }
    
    // knots和mult
    std::vector<double> knot_vec;
    knot_vec.reserve(knot_count);
    for (int i = 0; i < knot_count; i++)
    {
        double *pos = knot_pos + i;
        knot_vec.emplace_back(*pos);
    }
    std::vector<double> newKnots;
    std::vector<int> newMults;
    ReaderGeometryConvertHelper::ConvertKnotAndMult(knot_vec, newKnots, newMults);

    std::shared_ptr<AMCAX::Geom3BSplineCurve> geom3_bcurve = weights==nullptr? std::make_shared<AMCAX::Geom3BSplineCurve>(
        amx_ctrl_point, newKnots, newMults, degree):std::make_shared<AMCAX::Geom3BSplineCurve>(
        amx_ctrl_point,weights_vector, newKnots, newMults, degree);
    
    if(isPeriodic) geom3_bcurve->SetPeriodic();
    // LOG_DEBUG("make_edge_from_bs3curve end");
    AMCAX::TopoBuilder TB;
    AMCAX::TopoEdge res = AMCAX::MakeEdge(geom3_bcurve);

    TB.UpdateEdge(res,geom3_bcurve, AMCAX::Precision::Confusion());
    return res;
}

// AMCAX::SurfaceType
AMCAX::TopoFace ConvertFace(const FACE *face, AMCAX::TopoWire *outer)
{
    if (!face) {
        LOG_ERROR("face is null") ;
        return AMCAX::TopoFace() ;
    }

    AMCAX::TopoBuilder builder;
    AMCAX::TopoFace topoFace;
    SURFACE *tmpSurf = face->geometry();
    if (tmpSurf == nullptr)
    {
        return topoFace;
    }
    if (is_PLANE(tmpSurf)) {
        return ConvertPlane(face,outer) ;
    }
    if (is_CONE(tmpSurf)) {
        return ConvertCone(face,outer) ;
    }
    if (is_SPHERE(tmpSurf)) {
        return ConvertSphere(face,outer) ;
    }
    if (is_TORUS(tmpSurf)) {
        return ConvertTorus(face,outer) ;
    }
    if (is_SPLINE(tmpSurf)) {
        return ConvertBsurface(face,outer) ;
    }
    LOG_ERROR("not support face type: {},", tmpSurf->type_name());
    return topoFace;
}

AMCAX::TopoFace ConvertPlane(const FACE *face, AMCAX::TopoWire *outer)
{
    if (!face) {
        LOG_ERROR("face is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    if (!face->geometry()) {
        LOG_ERROR("geometry is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    PLANE *surface = static_cast<PLANE *>(face->geometry());
        
    SPAunit_vector rootNorm = surface->normal();

    AMCAX::Point3 amcaxPlanePos = ReaderGeometryConvertHelper::ConvertPoint(surface->root_point()) ;
    AMCAX::Direction3 amcaxPlaneDir(rootNorm.x(), rootNorm.y(), rootNorm.z());

    std::shared_ptr<AMCAX::Geom3Plane> geom3Plane = AMCAX::MakeGeom3Plane(amcaxPlanePos, amcaxPlaneDir);
    
    TopoFace res;
    TopoBuilder TB;
    TB.MakeFace(res,geom3Plane,AMCAX::Precision::Confusion());
    return res;
}

AMCAX::TopoFace ConvertCylinder(const FACE *face, AMCAX::TopoWire *outer)
{
    if (!face) {
        LOG_ERROR("face is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    if (!face->geometry()) {
        LOG_ERROR("geometry is null") ;
        return AMCAX::TopoFace() ;   
    }
    LOG_ERROR("unsupport cylinder") ;
    return AMCAX::TopoFace();
}

AMCAX::TopoFace ConvertCone(const FACE *face, AMCAX::TopoWire *outer)
{
    if (!face) {
        LOG_ERROR("face is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    if (!face->geometry()) {
        LOG_ERROR("geometry is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    AMCAX::TopoBuilder TB;
    AMCAX::TopoFace res;
    CONE *surface = static_cast<CONE *>(face->geometry());
    double ma_len = surface->major_axis().len_sq();
    double ratio =surface->radius_ratio();

    SPAposition tmpConePos = surface->root_point();
    SPAunit_vector tmpConeDir = surface->direction();
    SPAvector majAxis = surface->major_axis();
    double radius = sqrt(majAxis.x() * majAxis.x() + majAxis.y() * majAxis.y() + majAxis.z() * majAxis.z());

    AMCAX::Point3 coneRoot(tmpConePos.x(), tmpConePos.y(), tmpConePos.z());
    AMCAX::Direction3 coneDir(tmpConeDir.x(), tmpConeDir.y(), tmpConeDir.z());

    if (surface->sine_angle() == 0.0)
    {
        // 圆柱面
        // LOG_DEBUG("make_cylinder");
        AMCAX::Frame3 frame(coneRoot, coneDir);
        AMCAX::Direction3 majDir(majAxis.x(), majAxis.y(), majAxis.z());
        frame.SetXDirection(majDir);
        AMCAX::MakeGeom3CylindricalSurface cylinder_surface(frame, radius);
        TB.MakeFace(res, cylinder_surface.Value(), AMCAX::TopoLocation(), AMCAX::Precision::Confusion());
        return res;
    }

    // 获取圆锥顶点
    const cone *real = static_cast<const cone *>(&(surface->equation()));
    if (!real) {
        LOG_ERROR("invalid conne") ;
        return res ;
    }
    SPAposition apex = real->get_apex();
    AMCAX::Point3 amcax_apex(apex.x(), apex.y(), apex.z());

    // LOG_DEBUG("make_cone");
    AMCAX::MakeGeom3ConicalSurface cone_surface(coneRoot, amcax_apex, radius, 0.0);
    TB.MakeFace(res, cone_surface.Value(), AMCAX::TopoLocation(), AMCAX::Precision::Confusion());
    return res;
}

AMCAX::TopoFace ConvertSphere(const FACE *face, AMCAX::TopoWire *outer)
{
    if (!face) {
        LOG_ERROR("face is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    if (!face->geometry()) {
        LOG_ERROR("geometry is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    SPHERE *surface = static_cast<SPHERE *>(face->geometry());
    SPAposition centrePos = surface->centre();

    AMCAX::Point3 sphereCentre = ReaderGeometryConvertHelper::ConvertPoint(centrePos) ;
    AMCAX::Direction3 dir1(0.0, 0.0, 1.0);
    AMCAX::Direction3 dir2(0.0, 1.0, 0.0);

    AMCAX::Frame3 frame(sphereCentre, dir1, dir2);
    auto sphere = std::make_shared<AMCAX::Geom3SphericalSurface>(frame, surface->radius());
    AMCAX::TopoBuilder TB;     
    AMCAX::TopoFace res;
    TB.MakeFace(res, sphere, AMCAX::Precision::Confusion());
    return res;
}

AMCAX::TopoFace ConvertTorus(const FACE *face, AMCAX::TopoWire *outer)
{
    if (!face) {
        LOG_ERROR("face is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    if (!face->geometry()) {
        LOG_ERROR("geometry is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    TORUS *surface = cast_TORUS(face->geometry());  
    //TORUS *surface = static_cast<TORUS *>(face->geometry());
    // SPAposition center_pos = surface->centre();
    SPAunit_vector tmpNorm = surface->normal();

    AMCAX::Point3 torusCenter = ReaderGeometryConvertHelper::ConvertPoint(surface->centre()) ;
    AMCAX::Direction3 dir1(tmpNorm.x(), tmpNorm.y(), tmpNorm.z());
    AMCAX::Frame3 frame(torusCenter, dir1);

    double majorRadius = surface->major_radius();
    double minorRadius = surface->minor_radius();

    // auto tsurface = surface->trans_surface();
    // torus* tori = static_cast<torus*>(tsurface);
    // tmpNorm = tori->uv_oridir;
    
    

    if(std::abs(majorRadius) > std::abs(minorRadius))
    {
        // LOG_DEBUG("donut torus") ;
        AMCAX::TopoBuilder TB;     
        AMCAX::TopoFace res;
        auto geom3Rorus = std::make_shared<AMCAX::Geom3ToroidalSurface>(frame, std::abs(majorRadius), std::abs(minorRadius));
        TB.MakeFace(res, geom3Rorus, AMCAX::Precision::Confusion());
        return res;
    }
    // lemon torus
    else if (majorRadius < 0 && -majorRadius < std::abs(minorRadius))
    {
        // LOG_DEBUG("lemon torus") ;
        frame.ZReverse();
        auto lemon_torus = std::make_shared<AMCAX::Geom3ToroidalSurface>(frame, std::abs(majorRadius), std::abs(minorRadius));

        long double vMin = std::acos( std::abs(majorRadius)/ minorRadius);
        auto trimSurface = std::make_shared<AMCAX::Geom3TrimmedSurface>(
            lemon_torus,
            0.0, (double)2.0 * M_PI,
            double(M_PI - vMin), double(M_PI + vMin)
        ) ;
        AMCAX::TopoBuilder TB;     
        AMCAX::TopoFace res;    
        TB.MakeFace(res, trimSurface, AMCAX::Precision::Confusion());    
        return res;
    }
    //apple torus
    else if(std::abs(minorRadius) > majorRadius && majorRadius > 0)
    {
        // LOG_DEBUG("apple torus") ;
        AMCAX::TopoBuilder TB;     
        AMCAX::TopoFace res;
        auto geom3Rorus = std::make_shared<AMCAX::Geom3ToroidalSurface>(frame, std::abs(majorRadius), std::abs(minorRadius));
        TB.MakeFace(res, geom3Rorus, AMCAX::Precision::Confusion());
        return res;
    }
    //vortex torus
    else if(std::abs(minorRadius) == majorRadius)
    {
        // LOG_DEBUG("vortex torus") ;
        AMCAX::TopoBuilder TB;     
        AMCAX::TopoFace res;
        auto geom3Rorus = std::make_shared<AMCAX::Geom3ToroidalSurface>(frame, std::abs(majorRadius), std::abs(minorRadius));
        TB.MakeFace(res, geom3Rorus, AMCAX::Precision::Confusion());
        return res;
    }

    return AMCAX::TopoFace();

}
AMCAX::TopoFace ConvertBsurface(const FACE *face, AMCAX::TopoWire *outer)
{
    if (!face) {
        LOG_ERROR("face is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    if (!face->geometry()) {
        LOG_ERROR("geometry is null") ;
        return AMCAX::TopoFace() ;   
    }
    
    ReaderGeometryConvertHelper::GetBsplineParameters(face);
    SURFACE * S = face->geometry();
    const surface & s = S->equation();
    bs3_surface bs3 = ((const spline&)s).sur();

    // 获取样条曲面参数
    int dim, rational_u, rational_v, form_u, form_v, pole_u, pole_v, ctrl_num_u, ctrl_num_v;
    SPAposition *ctr_point_pos = nullptr;
    double *weights = nullptr;
    int degree_u = 0, degree_v = 0;
    int num_knots_u = 0, num_knots_v = 0;
    double *knots_u, *knots_v = nullptr;
    bs3_surface_to_array(bs3,
                            dim, rational_u, rational_v, form_u, form_v, pole_u, pole_v,
                            ctrl_num_u, ctrl_num_v, ctr_point_pos, weights,
                            degree_u, num_knots_u, knots_u, degree_v, num_knots_v, knots_v);
    bool periodic_u = bs3_surface_periodic_u(bs3);
    bool periodic_v = bs3_surface_periodic_v(bs3);

    // 控制点转amcax
    AMCAX::Array2<AMCAX::Point3> amcax_ctrl_points(ctrl_num_u, ctrl_num_v);
    for (int i = 0; i < ctrl_num_u; i++)
    {
        std::vector<AMCAX::Point3> tmp_vector;
        tmp_vector.reserve(ctrl_num_v);
        for (int j = 0; j < ctrl_num_v; j++)
        {
            SPAposition pos = ctr_point_pos[i * ctrl_num_v + j];
            tmp_vector.emplace_back(pos.x(), pos.y(), pos.z());
        }
        amcax_ctrl_points.FillRow(i, tmp_vector);
    }
    if (ctr_point_pos != nullptr)
    {
        delete[] ctr_point_pos;
    }
    
    // 权重转amcax
    
    AMCAX::Array2<double> weights_array(ctrl_num_u, ctrl_num_v);
    if(weights!=nullptr)
    {
            for (int i = 0; i < ctrl_num_u; i++)
        {
            std::vector<double> tmp_vector;
            tmp_vector.reserve(ctrl_num_v);
            for (int j = 0; j < ctrl_num_v; j++)
            {
                tmp_vector.emplace_back(weights[i * ctrl_num_v + j]);
            }
            weights_array.FillRow(i, tmp_vector);
        }

    }
    

    // u方向的knots和mult
    std::vector<double> knot_vec_u;
    knot_vec_u.reserve(num_knots_u);
    for (int i = 0; i < num_knots_u; i++)
    {
        double *pos = knots_u + i;
        knot_vec_u.emplace_back(*pos);
    }
    std::vector<double> newKnots_u;
    std::vector<int> newMults_u;
    ReaderGeometryConvertHelper::ConvertKnotAndMult(knot_vec_u, newKnots_u, newMults_u);

    // v方向的knots和mult
    std::vector<double> knot_vec_v;
    knot_vec_v.reserve(num_knots_v);
    for (int i = 0; i < num_knots_v; i++)
    {
        double *pos = knots_v + i;
        knot_vec_v.emplace_back(*pos);
    }
    std::vector<double> newKnots_v;
    std::vector<int> newMults_v;
    ReaderGeometryConvertHelper::ConvertKnotAndMult(knot_vec_v, newKnots_v, newMults_v);

    AMCAX::TopoFace res=AMCAX::TopoFace();
    TopoBuilder TB;
    try
    { 
        std::shared_ptr<AMCAX::Geom3BSplineSurface> geom3_bsurf = weights!=nullptr?
        std::make_shared<AMCAX::Geom3BSplineSurface>(amcax_ctrl_points, weights_array,newKnots_u, newKnots_v, newMults_u, newMults_v,degree_u, degree_v, false, false)
        :std::make_shared<AMCAX::Geom3BSplineSurface>(amcax_ctrl_points, newKnots_u, newKnots_v, newMults_u, newMults_v,degree_u, degree_v, false, false);
    
        if(periodic_u) geom3_bsurf->SetUPeriodic();
        if(periodic_v) geom3_bsurf->SetVPeriodic();
        TB.MakeFace(res,geom3_bsurf,AMCAX::Precision::Confusion());
        // LOG_DEBUG("make Geom3Surface done.res");
    }catch(...)
    {
        LOG_ERROR("make Geom3Surface failed.");
    }

    return res;
}


}

AMCAX_EXCHANGE_NAMESPACE_END
